package org.xtetris;


public class Map {
	final int numRows , numCols;
	final int[][] data;
	
	final int[][] extra;
	final int[] flag;
	final static int EMPTY = 0;
	
	final static int EMPTY_ROW = 0;
	final static int FULL_ROW = 1;
	final static int NORMAL_ROW = 2;
	
	final static int MAX_EXTRA_ROWS = 8;
	
	public Map(int numRows , int numCols){
		this.numRows = numRows;
		this.numCols = numCols;
		data = new int[numRows][numCols];
		extra = new int[MAX_EXTRA_ROWS][numCols];
		flag = new int[numRows];
		clear();
	}
	
	void clear(){
		for (int i = 0; i < numRows; i++) {
			for (int j = 0; j < numCols; j++) {
				data[i][j] = EMPTY;
			}
		}
		
		for (int i = 0; i < extra.length; i++) {
			for (int j = 0; j < numCols; j++) {
				extra[i][j] = EMPTY;
			}
		}
	}
	
	int getDataAt(int row , int col){
		if(row >= 0){
			return data[row][col];			
		}else{
			return extra[- row][col];
		}
	}
	
	void setDataAt(int row , int col , int value){
		if(row >= 0){
			data[row][col] = value;
			if(value == EMPTY){
				boolean emptyRow = true;
				for (int i = 0; i < numCols; i++) {
					if(data[row][i] != EMPTY){
						emptyRow = false;
						break; 
					}
				}
				
				if(emptyRow){
					flag[row] = EMPTY_ROW;
				}else{
					flag[row] = NORMAL_ROW;
				}
			}else{
				boolean fullRow = true;
				for (int i = 0; i < numCols; i++) {
					if(data[row][i] == EMPTY){
						fullRow = false;
						break; 
					}
				}
				
				if(fullRow){
					flag[row] = FULL_ROW;
				}else{
					flag[row] = NORMAL_ROW;
				}
			}
		}else{
			extra[-row][col] = value;
		}
	}
	
	void clearRow(int row){
		for (int i = 0; i < numCols; i++) {
			data[row][i] = EMPTY;
		}
		flag[row] = EMPTY_ROW;
	}
	
	void pack(){
		for (int i = numRows - 1; i >= 0; i --) {
			if(flag[i] == NORMAL_ROW){
				for (int j = numRows - 1; j > i; j --) {
					if(flag[j] == FULL_ROW || flag[j] == EMPTY_ROW){
						clearRow(j);
						
						System.arraycopy(data[i], 0, data[j], 0, data[i].length);
						
						clearRow(i);
						
						flag[i] = EMPTY_ROW;					
						flag[j] = NORMAL_ROW;
						break;
					}
				}
			}
		}
		
		for (int i = 0; i < flag.length; i++) {
			if(flag[i] == FULL_ROW){
				clearRow(i);
			}
		}
		
		for (int i = 0; i < flag.length; i++) {
			if(flag[i] == FULL_ROW){
				throw new IllegalStateException("fail to deal with full rows");
			}
		}
	}
}
